/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package nsip.graph;

import java.util.Arrays;
import java.util.Observable;
import java.util.Observer;
import nsip.util.History;
import se.sics.isl.gui.DotDiagram;

/**
 *
 * @author nico.rehwaldt
 */
public abstract class HistorybasedGraphRenderer<T> implements Observer {
    
    private final History<T> history;
    private final int[][] data;
    private int currentIndex = 0;
    private final String name;
    private final int length;
    
    /**
     * Creates a new renderer for the given history
     * @param history
     */
    protected HistorybasedGraphRenderer(History<T> history, int length, String name) {
        this.history = history;
        this.data = createDataArray(length);
        this.name = name;
        this.length = length;
        
        history.addObserver(this);
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * Return graphs produced by this renderer
     * @return
     */
    protected abstract GraphInfo[] getGraphInfos();

    private int[][] createDataArray(int length) {
        int numGraphs = getGraphInfos().length;
        
        int[][] result = new int[numGraphs][length];
        for (int i = 0; i < numGraphs; i++) {
            Arrays.fill(result[i], 0);
        }
        return result;
    }

    /**
     * @param o
     * @param arg
     */
    public void update(Observable o, Object arg) {
        T item = (T) arg;

        int[] itemData = extractData(item, history);
        int index = getAndIncrementIndex();
        if (itemData.length != getGraphInfos().length) {
            throw new IllegalArgumentException("Extracted data has wrong amount of items");
        }
        
        for (int i = 0; i < getGraphInfos().length; i++) {
            data[i][index] = itemData[i];
        }
    }

    /**
     * Increment and return the value of current index
     * @return
     */
    private int getAndIncrementIndex() {
        return currentIndex++;
    }
    
    /**
     * Extract new data from the specified item and return the result for each
     * graph as an array of int.
     * 
     * @param item
     * @param history
     * @return
     */
    protected abstract int[] extractData(T item, History<T> history);

    /**
     * Return the data column for the given graph index. The column should have
     * the specified minimum length.
     * 
     * @param index
     * @return
     */
    public int[] getGraph(int index) {
        int displaySize = getDisplayLength();
        int startIndex = currentIndex > displaySize ? currentIndex - displaySize : 0;
        return Arrays.copyOfRange(data[index], startIndex, startIndex + displaySize);
    }

    /**
     * Return length of renderer
     * @return
     */
    public int getLength() {
        return length;
    }

    /**
     * Return slice in the diagram which is displayed
     * @return
     */
    public int getDisplayLength() {
        return 80;
    }

    /**
     * Return the display type for the graphs provided by this renderer
     * @return
     */
    public int getDisplayType() {
        return DotDiagram.NORMAL;
    }

    /**
     * Return constants to be displayed in the graph
     * @return
     */
    public ConstantInfo[] getConstants() {
        return new ConstantInfo[0];
    }
}
